package com.zed.api.games;

import java.util.List;
import java.util.Objects;

/**
 * 抽象的游戏关卡
 *
 * @author Zed
 */
public abstract class AbstractGameLevel<S, A extends Action> implements GameLevel<S, A> {

    private Game game;

    private Integer currentLevel;

    private GameLevel<S, A> parentGameLevel;
    private GameLevel<S, A> nextGameLevel;

    /**
     * 无参构造函数
     */
    protected AbstractGameLevel() {

    }

    protected AbstractGameLevel(Game game, GameLevel<S, A> parentGameLevel, GameLevel<S, A> nextGameLevel) {
        this.game = Objects.requireNonNull(game, "\"game\" cannot be null.");
        this.parentGameLevel = parentGameLevel;
        this.nextGameLevel = nextGameLevel;
    }


    @Override
    public Game getGame() {
        return this.game;
    }

    @Override
    public GameLevel<S, A> getParentLevel() {
        return this.parentGameLevel;
    }

    @Override
    public GameLevel<S, A> getNextLevel() {
        return this.nextGameLevel;
    }

    @Override
    public int getCurrentLevel() {
        if (this.currentLevel == null) {
            int result = 1;
            GameLevel<S, A> parentLevel = this.getParentLevel();
            while (!parentLevel.isFirst()) {
                parentLevel = parentLevel.getParentLevel();
                result++;
            }
            this.currentLevel = result;
        }
        return this.currentLevel;
    }

    /**
     * 确保支持的指令
     *
     * @param action {@link A},指令
     * @throws GameNonSupportActionException, 当前游戏关卡不支持的指令
     */
    protected void ensureSupportAction(A action) throws GameNonSupportActionException {
        for (Class<? extends A> supportAction : this.getSupportActions()) {
            if (supportAction.isAssignableFrom(action.getClass())) {
                return;
            }
        }
        throw new GameNonSupportActionException(action);
    }

    /**
     * 确保指令参数必填写
     *
     * @param action {@link A},指令
     * @throws GameActionParamVerifyException, 游戏指定参数校验列外
     */
    protected void ensureActionParamFilled(A action) throws GameActionParamVerifyException {
        List<String> mustFillParameters = action.getMustFillParameters();
        if (mustFillParameters.isEmpty()) return;
        for (String mustFillParameter : mustFillParameters) {
            Object parameter = action.getParameter(mustFillParameter);
            if (parameter == null) {
                throw new GameActionParamVerifyException(action);
            }
        }
    }


    @Override
    public final ActionReply invoke(A action) throws GameException {
        if (action == null) return new EmptyActionReply(this.getGame(), this);
        this.ensureSupportAction(action);
        this.ensureActionParamFilled(action);
        try {
            ActionReply actionReply = this.doInvoke(action);
            if (actionReply == null) return new EmptyActionReply(this.getGame(), this);
            return actionReply;
        } catch (Throwable e) {
            if (e instanceof GameException) {
                throw (GameException) e;
            }
            //包装成游戏异常
            throw new GameException(e);
        }
    }

    /**
     * 对调用的回复
     *
     * @param action {@link A},指令
     * @return {@link ActionReply},指令的回复
     */
    protected abstract ActionReply doInvoke(A action) throws Exception;

}
